package lzupdater.properties;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;

//LZRosterUpdater, a java client to update LZRoster
//Copyright (C) 2008 Fraskor from Krasus (e-mail: fraskor@gmail.com)
//
//This file is part of LZRosterUpdater.
//
//LZRosterUpdater is free software: you can redistribute it and/or modify
//it under the terms of the GNU General Public License as published by
//the Free Software Foundation, either version 3 of the License, or
//(at your option) any later version.
//
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with this program.  If not, see <http://www.gnu.org/licenses/>.

/**
 * 
 * @author Fraskor
 */
public abstract class PropertyElement {

	public abstract boolean isString();

	public abstract boolean isHashMap();

	public abstract PropertyElement get(String key);

	public abstract HashMapProperty getAsMap(String key);

	public abstract String getAsString(String key);

	public abstract ArrayList<String> toString(String header);

	public static StringProperty makeStringProperty(String value) {
		return new StringProperty(value);
	}

	public static HashMapProperty makeHashMapProperty() {
		return new HashMapProperty();
	}

	public abstract void clear();

	public final StringProperty toStringProperty() {
		if (this instanceof StringProperty) {
			return (StringProperty) this;
		}
		return null;
	}

	public final HashMapProperty toHashMapProperty() {
		if (this instanceof HashMapProperty) {
			return (HashMapProperty) this;
		}
		return null;
	}

	public String getAsString(String key, String defaultValue) {
		String resultat = this.getAsString(key);
		if (resultat == null) {
			resultat = defaultValue;
		}
		return resultat;
	}

	public static class StringProperty extends PropertyElement {
		private final String value;

		public StringProperty(String value) {
			this.value = value;
		}

		@Override
		public boolean isHashMap() {
			return false;
		}

		@Override
		public boolean isString() {
			return true;
		}

		@Override
		public PropertyElement get(String key) {
			return null;
		}

		@Override
		public HashMapProperty getAsMap(String key) {
			return null;
		}

		@Override
		public String getAsString(String key) {
			return null;
		}

		@Override
		public ArrayList<String> toString(String header) {
			ArrayList<String> resultat = new ArrayList<String>(1);
			resultat.add(String.format("%s = %s", header, value));
			return resultat;
		}

		@Override
		public String toString() {
			return value;
		}

		@Override
		public void clear() {
		}

	}

	public static class HashMapProperty extends PropertyElement implements
			Iterable<Entry<String, PropertyElement>> {
		private final HashMap<String, PropertyElement> value = new HashMap<String, PropertyElement>();

		@Override
		public boolean isHashMap() {
			return true;
		}

		@Override
		public boolean isString() {
			return false;
		}

		@Override
		public PropertyElement get(String key) {
			return value.get(key);
		}

		@Override
		public HashMapProperty getAsMap(String key) {
			PropertyElement elmt = value.get(key);
			return elmt == null ? null : elmt.toHashMapProperty();
		}

		@Override
		public String getAsString(String key) {
			PropertyElement elmt = value.get(key);
			return (elmt == null || !elmt.isString()) ? null : elmt
					.toStringProperty().value;
		}

		@Override
		public String toString() {
			ArrayList<String> tmp = this.toString(null);
			StringBuffer buffer = new StringBuffer("");
			Iterator<String> it = tmp.iterator();
			while (it.hasNext()) {
				buffer.append(it.next());
				if (it.hasNext()) {
					buffer.append("\n");
				}
			}
			return buffer.toString();
		}

		@Override
		public ArrayList<String> toString(String header) {
			ArrayList<String> resultat = new ArrayList<String>();
			if (header == null) {
				header = "";
			} else {
				header += ".";
			}
			for (Entry<String, PropertyElement> entry : this) {
				resultat.addAll(entry.getValue().toString(
						header + entry.getKey()));
			}
			if (resultat.size() > 0
					&& resultat.get(resultat.size() - 1).length() > 0)
				resultat.add("");
			return resultat;
		}

		public Iterator<Entry<String, PropertyElement>> iterator() {
			return value.entrySet().iterator();
		}

		public HashMapProperty getOrAddDir(String dirName) {
			PropertyElement resultat = value.get(dirName);
			if (resultat == null || !resultat.isHashMap()) {
				resultat = makeHashMapProperty();
				value.put(dirName, resultat);
			}
			return resultat.toHashMapProperty();
		}

		public void addProperty(String path, String value) {
			String[] dirs = path.split("\\.");
			if (dirs.length > 0)
				this.addProperty(dirs, 0, value);
		}

		private void addProperty(String[] dirs, int idx, String value) {
			if (idx == dirs.length - 1) {
				this.value.put(dirs[idx], new StringProperty(value));
			} else {
				getOrAddDir(dirs[idx]).addProperty(dirs, idx + 1, value);
			}
		}

		@Override
		public void clear() {
			value.clear();
		}

	}

}
